package com.runningrookie.aspect;

import com.runningrookie.annotation.ConcurrencyLock;
import com.runningrookie.domain.AjaxResult;
import com.runningrookie.service.ConcurrencyLockService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
@Slf4j
public class ConcurrencyLockAspect {
    ConcurrencyLockService concurrencyLockService;
    @Autowired
    ConcurrencyLockAspect(ConcurrencyLockService concurrencyLockService) {
        this.concurrencyLockService = concurrencyLockService;
    }
    @Around("@annotation(concurrencyLock)")
    public Object around(ProceedingJoinPoint joinPoint, ConcurrencyLock concurrencyLock) throws Throwable {
        long threadId = Thread.currentThread().getId();
        Object[] args = joinPoint.getArgs();
        if (args.length == 0) {
            return joinPoint.proceed();
        }
        // 通过反射获取值
        String invokeMethodName = "get" + concurrencyLock.businessUniqueNoKey().substring(0, 1).toUpperCase() + concurrencyLock.businessUniqueNoKey().substring(1);
        // 获取Order类的Class对象
        Class<?> clazz = args[0].getClass();
        // 获取getOrderNo方法的Method对象
        Method method = clazz.getMethod(invokeMethodName);

        // 调用getOrderNo方法并获取返回值
        String businessUniqueNo = method.invoke(args[0]).toString();
        Boolean isSuccessLock = concurrencyLockService.tryLock(concurrencyLock.businessNode(), businessUniqueNo);
        if (!isSuccessLock) {
            log.info("{}加锁失败，请稍后重试", threadId);
            return AjaxResult.error("加锁失败，请稍后重试");
        }
        try {
            log.info("{}开始执行业务逻辑", threadId);
            joinPoint.proceed();
        } finally {
            concurrencyLockService.unLock(concurrencyLock.businessNode(), businessUniqueNo);
        }
        return joinPoint.proceed();
    }
}
